package cn.edu.zju.gis.disasterBE.sever.service;

import cn.edu.zju.gis.disasterBE.sever.dao.UserAssistantDAO;
import cn.edu.zju.gis.disasterBE.sever.dao.UserDAO;
import cn.edu.zju.gis.disasterBE.sever.entity.User;
import cn.edu.zju.gis.disasterBE.sever.entity.assistants.UserAssistant;
import cn.edu.zju.gis.disasterBE.sever.entity.global.MyResponse;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSendException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.List;
import java.util.Random;

@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class UserService {
    protected final UserDAO dao;
    protected final UserAssistantDAO userAssistantDAO;
    @Autowired
    private JavaMailSender mailSender;
    @Autowired
    private TokenService tokenService;

    private static <E> boolean checkPwd(String pwd, MyResponse<E> myResponse)
    {
        if (pwd.length() > 50)
        {
            myResponse.setMsg("The password is to long. An appropriate password must contain number and letters in both lowercase form and uppercase form." +
                    "Besides, the length of the password should be controlled between 6 characters and 50 characters.");
            return true;
        }
        else if (pwd.length() < 6)
        {
            myResponse.setMsg("The password is to short. An appropriate password must contain number and letters in both lowercase form and uppercase form." +
                    "Besides, the length of the password should be controlled between 6 characters and 50 characters.");
            return true;
        }
        else
        {
            boolean lower = false, upper = false, num = false;
            for(int i = 0; i < pwd.length(); i++)
            {
                if (pwd.charAt(i) >= 'a' && pwd.charAt(i) <= 'z')
                {
                    lower = true;
                }
                else if (pwd.charAt(i) >= 'A' && pwd.charAt(i) <= 'Z')
                {
                    upper = true;
                }
                else if (pwd.charAt(i) >= '0' && pwd.charAt(i) <= '9')
                {
                    num = true;
                }
                else
                {
                    myResponse.setMsg("The password contains illegal character， please retry it!");
                    return true;
                }
            }
            if (!num || !lower || !upper)
            {
                myResponse.setMsg("The password must contain number and letters in both lowercase form and uppercase form, please retry it!");
                return true;
            }
        }
        return false;
    }
    public User getByID(String id)
    {
        Integer nid = null;
        if(id != null)
            nid = Integer.valueOf(id);
        return dao.getByID(nid);
    }

    private static boolean checkUserData(MyResponse<User> myResponse)
    {
        User user = myResponse.getData();
        try {
            if(user.getAddress1().length() >= 100 || (user.getAddress2() != null && user.getAddress2().length() >= 100)) {
                myResponse.setMsg("The address is to long, please control the length under 100 characters");
                return false;
            }
            else if (user.getMailAddr().length() >= 50 || user.getMailAddr().length() <= 5) {
                myResponse.setMsg("The email should be shorter than 50 characters and longer than 5 character");
                return false;
            }
            else if (user.getNickName().length() >= 50 || user.getNickName().length() <= 1) {
                myResponse.setMsg("The nick name should be shorter than 50 characters and longer than 1 character");
                return false;
            }
            else if (user.getTitle().length() >= 50 || user.getTitle().length() <= 1) {
                myResponse.setMsg("The title should be shorter than 50 characters and longer than 1 character");
                return false;
            }
            else if(user.getWorkPlace().length() >= 100 || user.getWorkPlace().length() <= 1) {
                myResponse.setMsg("The work place should be shorter than 100 characters and longer then 1 character");
                return false;
            }
            else if (user.getAffiliation().length() >= 100 || user.getAffiliation().length() <= 1) {
                myResponse.setMsg("The affiliation should be shorter than 100 characters and longer then 1 character");
                return false;
            }
            else if (user.getZipCode().length() >= 20 || user.getZipCode().length() <= 1) {
                myResponse.setMsg("The zip code should be shorter than 20 characters and longer then 1 character");
                return false;
            }
            else if (user.getCity().length() >= 50 || user.getCity().length() <= 1) {
                myResponse.setMsg("The city should be shorter than 100 characters and longer then 1 character");
                return false;
            }

        } catch (NullPointerException e)
        {
            myResponse.setMsg("Information of user is not complete!");
        }
        return true;
    }

    public MyResponse<User> registerUser(String json)
    {
        //System.out.println(json);
        MyResponse<User> myResponse = new MyResponse<>();
        User user = JSON.parseObject(json,User.class);
        System.out.println(user);
        myResponse.setData(user);
        myResponse.setState(false);
        if (!checkUserData(myResponse) || checkPwd(user.getPwd(), myResponse))
        {
            return myResponse;
        }
        if (dao.registerUser(user))
        {
            myResponse.setState(true);
            myResponse.setMsg("Register successfully");
        }
        else
        {
            myResponse.setMsg("The mail address is already exists");
        }
        System.out.println(myResponse);
        return myResponse;
    }
    public MyResponse<User> updateUser(String json)
    {
        User user = JSON.parseObject(json,User.class);
        MyResponse<User> myResponse = new MyResponse<>();
        myResponse.setData(user);
        myResponse.setState(false);
        if(!checkUserData(myResponse)) {
            return myResponse;
        }
        return dao.updateUser(user);
    }
    public MyResponse<User> loginUser(String mailAddr, String pwd)
    {
        User user = new User();
        user.setMailAddr(mailAddr);
        user.setPwd(pwd);
        MyResponse<User> myResponse = dao.loginUser(user);
        if(!myResponse.getState())  return myResponse;
        String token = tokenService.getToken(myResponse.getData());
        myResponse.setMsg(token);
        System.out.println(myResponse);
        return myResponse;

    }
    public MyResponse<String> verifyEmail(String mailAddr)
    {
        MyResponse<String> myResponse = new MyResponse<>();
        //如果邮箱已经存在了，那就必须更换
        if (dao.isExistMail(mailAddr))
        {
            myResponse.setData(null);
            myResponse.setMsg("This email has already been registered!");
            myResponse.setState(false);
            return myResponse;
        }

        Random r = new Random();
        int tmp = r.nextInt(10);
        if(tmp == 0) tmp += 1;
        for (int i = 0; i < 5; i ++)
        {
            int x = r.nextInt(10);
            tmp = tmp *10 + x;
        }
        String verification = String.valueOf(tmp);
        System.out.println(verification);
        myResponse.setData(verification);
        try {
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            simpleMailMessage.setSubject("Register");
            simpleMailMessage.setText("Welcome to our system! Your verification is " + verification + ", you can use it to register an account!");
            simpleMailMessage.setTo(mailAddr);
            simpleMailMessage.setFrom("medicalge@163.com");
            mailSender.send(simpleMailMessage);
        } catch (MailSendException e)
        {
            myResponse.setState(false);
            myResponse.setMsg("Fail to send! Please check the mail address and try again!");
            System.out.println(myResponse);
            return myResponse;
        }
        myResponse.setMsg("Send successfully! Please check the mail in your mailbox!");
        myResponse.setState(true);
        System.out.println(myResponse);
        return myResponse;
    }

    public MyResponse<String> changePwd(User user, String newPwd)
    {
        User tmp = dao.getByID(user.getUid());
        MyResponse<String> myResponse = new MyResponse<>();
        if(tmp.getPwd().equals(user.getPwd()))
        {
            if (checkPwd(newPwd, myResponse))
            {
                return myResponse;
            }
            int ans = dao.updatePwdByUID(newPwd,user.getUid());
            if(ans == 1)
            {
                myResponse.setState(true);
                myResponse.setMsg("update successfully");
            }
            else
            {
                myResponse.setState(false);
                myResponse.setMsg("Unknown wrong in database");
            }
        }
        else
        {
            myResponse.setState(false);
            myResponse.setMsg("The old password you input is not the same as the password stored in database!");
        }
        return myResponse;
    }

    public MyResponse<String> forgetPwd(String mailAddr)
    {
        MyResponse<String> myResponse = new MyResponse<>();
        User user = dao.getByMail(mailAddr);
        try {
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            simpleMailMessage.setSubject("Find Password");
            simpleMailMessage.setText("Dear "+user.getNickName()+",\n    your password is "+user.getPwd());
            simpleMailMessage.setTo(mailAddr);
            simpleMailMessage.setFrom("medicalge@163.com");
            mailSender.send(simpleMailMessage);
        } catch (MailSendException e)
        {
            myResponse.setState(false);
            myResponse.setMsg("Fail to send! Please check the mail address and try again!");
            //System.out.println(myResponse);
            return myResponse;
        }
        myResponse.setMsg("Send successfully! Please check the mail in your mailbox!");
        myResponse.setState(true);
        //System.out.println(myResponse);
        return myResponse;
    }

    public MyResponse<String> authentication(String mailAddr)
    {
        MyResponse<String> myResponse = new MyResponse<>();
        UserAssistant userAssistant = new UserAssistant();
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        User user = dao.getByMail(mailAddr);
        userAssistant.setApplyTime(timestamp);
        userAssistant.setMailAddr(mailAddr);
        userAssistant.setAffiliation(user.getAffiliation());
        userAssistant.setName(user.getFirstName() + user.getLastName());
        userAssistant.setWorkPlace(user.getWorkPlace());
        userAssistant.setTitle(user.getTitle());
        //先将数据插入数据库
        if(!userAssistantDAO.insertUsers(userAssistant))
        {
            myResponse.setState(false);
            myResponse.setMsg("You have applied already! Please wait for the administrator to authenticate!");
            myResponse.setData(null);
            return myResponse;
        }
        //发送邮件
        try {
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            simpleMailMessage.setSubject("Authentication");
            simpleMailMessage.setText("We have receive your application and we will authenticate it soon!");
            simpleMailMessage.setTo(mailAddr);
            simpleMailMessage.setFrom("medicalge@163.com");
            mailSender.send(simpleMailMessage);
        } catch (MailSendException e)
        {
            myResponse.setState(false);
            myResponse.setMsg("Fail to send! Please check the mail address and try again!");
            System.out.println(myResponse);
            return myResponse;
        }

        myResponse.setState(true);
        myResponse.setMsg("Apply successfully!");
        System.out.println("apply successfully");
        return myResponse;
    }

    public MyResponse<List<UserAssistant>> getApplication()
    {
        MyResponse<List<UserAssistant>> myResponse = new MyResponse<>();
        myResponse.setMsg("Success");
        myResponse.setData(userAssistantDAO.getApplications());
        myResponse.setState(true);
        System.out.println("get successfully");
        return myResponse;
    }

    public MyResponse<String> auditApplication(String mailAddr)
    {
        MyResponse<String> myResponse = new MyResponse<>();
        User user = dao.getByMail(mailAddr);
        if ( dao.updateUtypeByUID(user.getUid()) == 0)
        {
            myResponse.setState(false);
            myResponse.setData(null);
            myResponse.setMsg("Fail to audit");
            System.out.println("fail to update");
            return myResponse;
        }
        System.out.println("update successfully");
        if ( userAssistantDAO.deleteByMail(mailAddr) == 0)
        {
            myResponse.setState(false);
            myResponse.setData(null);
            myResponse.setMsg("Fail to audit");
            System.out.println("fail to delete");
            return myResponse;
        }
        myResponse.setMsg("Audit successfully");
        myResponse.setState(true);
        myResponse.setData(null);
        System.out.println("audit successfully");
        return myResponse;
    }
}
